﻿//-----------------------------------------------------------------------
// <copyright file="CommandHandlingManager.cs" author="Artak Mkrtchyan">
//     Creative Commons - GNU General Public License (http://creativecommons.org/licenses/GPL/2.0/
// </copyright>
// <author>Artak Mkrtchyan</author>
// <email>mkArtak@gmail.com</email>
// <date>21/10/2012</date>
//-----------------------------------------------------------------------
using ConsoleHoster.Common.Model;
using ConsoleHoster.Common.Utilities;
using ConsoleHoster.Common.ViewModel;
using System;
using System.Collections.Generic;

namespace ConsoleHoster.Model
{
	public class CommandHandlingManager : ICommandHandlingManager
	{
		private readonly IConsoleVM consoleVM;
		private readonly ILogger logger;
		private readonly IDictionary<string, Tuple<bool, Action<string>>> commandHandlers;

		public CommandHandlingManager(IConsoleVM argConsoleVM, ILogger argLogger)
		{
			if (argConsoleVM == null)
			{
				throw new ArgumentNullException("argConsoleVM");
			}

			this.logger = new ComponentLogger("CommandHandlingManager", argLogger);
			this.consoleVM = argConsoleVM;
			this.commandHandlers = new Dictionary<string, Tuple<bool, Action<string>>>();
		}

		/// <summary>
		/// Handles the command request to exectue before actual execution
		/// </summary>
		/// <param name="argCommand">The command requested to run</param>
		/// <returns>A boolean value indicating whether to process with further steps of running the command or not</returns>
		public bool PreProcessCommand(string argCommand)
		{
			bool tmpResult = false;

			Action<string> tmpHandler;
			if (this.TryGetHandlersForCommand(argCommand, true, out tmpHandler))
			{
				try
				{
					this.logger.LogMessage("PreProcessCommand for command: {0}", argCommand);
					tmpHandler(argCommand);
				}
				catch (Exception ex)
				{
					this.logger.LogError("Failed to execute pre-process handler for command '{0}'. Details: {1}", argCommand, ex.ToString());
				}
				tmpResult = true;
			}

			return tmpResult;
		}

		public void PostProcessCommand(string argCommand)
		{
			Action<string> tmpHandler;
			if (this.TryGetHandlersForCommand(argCommand, false, out tmpHandler))
			{
				try
				{
					this.logger.LogMessage("PostProcessCommand for command: {0}", argCommand);
					tmpHandler(argCommand);
				}
				catch (Exception ex)
				{
					this.logger.LogError("Failed to execute the command handler for command: {0}. Details: {1}", argCommand, ex.ToString());
				}
			}
		}

		public void RegisterPreProcessCommandHandler(string argCommand, Action<string> argHandler)
		{
			this.RegisterCommandHandler(argCommand, argHandler, true);
		}

		public void RegisterPostProcessCommandHandler(string argCommand, Action<string> argHandler)
		{
			this.RegisterCommandHandler(argCommand, argHandler, false);
		}

		private void RegisterCommandHandler(string argCommand, Action<string> argHandler, bool isPreProcessHandler)
		{
			this.logger.LogMessage("RegisterCommandHandler for command: {0}", argCommand);
			if (String.IsNullOrWhiteSpace(argCommand))
			{
				throw new ArgumentNullException("argCommand");
			}
			if (argHandler == null)
			{
				throw new ArgumentNullException("argHandler");
			}

			string tmpCommand = argCommand.Trim().ToLower();
			if (this.IsHandlerRegisteredForCommand(tmpCommand))
			{
				throw new ApplicationException(String.Format("There is already a handler registerd for the command: {0}", argCommand));
			}

			this.commandHandlers.Add(tmpCommand, new Tuple<bool, Action<string>>(isPreProcessHandler, argHandler));
			this.logger.LogMessage("RegisterCommandHandler for command: {0} succeeded", argCommand);
		}

		private bool TryGetHandlersForCommand(string argCommand, bool argGetPreProcessHandler, out Action<string> argHandlers)
		{
			bool tmpResult = false;

			Tuple<bool, Action<string>> tmpHandlers;
			if (this.commandHandlers.TryGetValue(argCommand.Trim().ToLower(), out tmpHandlers) && tmpHandlers.Item1 == argGetPreProcessHandler)
			{
				argHandlers = tmpHandlers.Item2;
				tmpResult = true;
			}
			else
			{
				argHandlers = null;
			}

			return tmpResult;
		}

		private bool IsHandlerRegisteredForCommand(string argCommand)
		{
			return this.commandHandlers.ContainsKey(argCommand.Trim().ToLower());
		}

		private IConsoleVM ConsoleVM
		{
			get
			{
				return this.consoleVM;
			}
		}
	}
}
